import gobject
from ui import uiconstants as uicon
from messaging2 import ahconstants as ahcon
from setup.fvconstants import LIVE_AUDIO_PORT
import gstcomponents
import recordsrc
import gst
import os

class MixerInterface(gobject.GObject):
    __gsignals__ = {
                    
            # create signals that will be emitted from mixer 
            
            # emitted when the message finished playing back
            'end_message' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,
                    (gobject.TYPE_INT,)),
            # user_idle is when no incoming packets from network (no packets for 5 seconds)
            'user_idle' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,
                    (gobject.TYPE_PYOBJECT,)),
            # user_active is when packets start to come in from network (new packets for 5 secs)
            'user_active' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,
                    (gobject.TYPE_PYOBJECT,)), 
            'ack_push_to_talk' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,
                    (gobject.TYPE_INT,)),
                    
            'started_record' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,
                    (gobject.TYPE_INT,)),
            'stopped_record' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,
                    (gobject.TYPE_INT,)),
            'started_play' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,
                    (gobject.TYPE_INT,)),
            'stopped_play' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,
                    (gobject.TYPE_INT,)),
            'my_ssrc' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,
                    (gobject.TYPE_UINT,)),

    }

    def __init__( self, live_audio_dest):
        """
            @param live_audio_dest: the broadcast address that the live audio needs to be sent to
            @type live_audio_dest: String
        """
        gobject.GObject.__init__(self)
        
        self._file_sender = gstcomponents.FileInputSender(LIVE_AUDIO_PORT)
        self._file_sender.connect('eos', self._fileFinished)
        self._rtp_receiver = gstcomponents.RtpStreamsReceiver(LIVE_AUDIO_PORT, True)
        self._rtp_receiver.connect('new-rtp-stream', self._newRTPStream)
        self._rtp_receiver.connect('rtp-stream-timeout', self._timeoutRTPStream)
        
        self._mixers = {}      # map guid to pipelines
        self._file_players = {}
        self._file_control = {}
        self._file_finished = {}        # map id to file finished True/False
        self._inputs = {}                # map guid to their type and properties                            #     to notify
        self._mixer_params = {}        # maps guid to (volume, pan)
        
        self._my_ssrc = 0
        
        self._mic_controller = recordsrc.MicController(live_audio_dest, 
                                                        LIVE_AUDIO_PORT)
        self._mic_controller.connect( 'my_ssrc', self._startTalk )
        
        self._path = ahcon.MESSAGING_PATH+'apps/audio/'
        if not os.path.exists(self._path):
            print "MixerInterface: Creating path for audio"
            os.makedirs(self._path)
        self.temp_rec_file_name = self._path + "temp_audio.wav"

    def _startTalk(self, obj, ssrc):
        print "My SSRC:",ssrc
        self._my_ssrc = ssrc
        # silence my volume
        self._mixer_params[self._my_ssrc] = (0,0)
        self.emit('my_ssrc', ssrc)
        
    def _newRTPStream(self, obj, session, ssrc, pt, id):
        """
            Callback when new RTP stream appears in the mixer
            @param obj: L{RtpStreamsReceiver}
        """
        print "New RTP stream:",session,ssrc,pt,id
        
        self._mixers[ssrc] = self._rtp_receiver.getMixer( id )
        volume, pan = self._mixer_params.get(ssrc, (1,0) )
        self._mixers[ssrc].setVolume(volume)
        self._mixers[ssrc].setPan(pan)

    def _timeoutRTPStream( self, obj, session, ssrc, pt, id):
        print "Timeout RTP stream:",session,ssrc,pt,id
        if ssrc in self._mixers:
            self._mixers[ssrc].remove()
        self._mixers.pop(ssrc)
        self._mixer_params.pop(ssrc, None)

    def _fileFinished(self, obj, id):
        self._file_finished[id] = True
        print "Finished playing",id
        
    def onAddInput(self, obj, properties ):
        """
            Add an input to the audio mixer.  
            The input can be an audio message or network stream.
            @param guid:
            @type guid: Number
            @param properties: type; IP address, port for network and filename for message
            @type properties: Dictionary
        """
        if properties.get('status', uicon.OFFLINE) == uicon.OFFLINE:
            return
        guid = properties['id']
        print "Adding INPUT", guid
        self._inputs[guid] = properties
        
    def onChange(self, obj, ui_data):
        """
            When state changes from either background or muted or inactive
            @param ui_data: id, volume, pan
            @type ui_data: Dictionary
        """
        guid = ui_data['id']
        volume = ui_data['volume']
        pan = ui_data['pan']
        if pan > 1:
            pan = 1
        elif pan < -1:
            pan = -1

        # if object type is modifiable
        if ui_data['type'] not in [uicon.FV, uicon.SERVICE, uicon.PHONE, uicon.AUDIOMSG]:
            print "MIXER: Ignored",type
            return
        
        # if it was moved out of the playback area, stop it
        if volume < 0:
            if guid in self._file_players:
                player = self._file_players[guid]
                ssrc = player.getSsrc()
                self._file_finished.pop(player.getID())
                player.stop()
                player.remove()
                self._file_players.pop(guid)
                self._mixers[ssrc].remove()
                self._mixers.pop(ssrc)
                self._mixer_params.pop(ssrc)
            return
        
        # if the node is offline, then ignore
        properties = self._inputs.get(guid, None)
        if properties == None or properties.get('status', uicon.OFFLINE) == uicon.OFFLINE:
            return
        
        # handle files
        if ui_data['type'] is uicon.AUDIOMSG:
            if guid in self._file_players:
                self._file_players[guid].setVolume( volume )
                self._file_players[guid].setPan( pan )
                # check if file finished playing back and replay
                if self._file_finished[self._file_players[guid].getID()]:
                    self._file_control[guid].play()
                    self._file_finished[self._file_players[guid].getID()] = False
                    print "Replaying"
                return
            else:
                # create new pipeline for this guid
                print "New or Inactive Input",guid
                print "MIXER: Playing",properties['url']
                self._startMessage( guid, properties['url'], volume, pan )
 
        # handle network 
        ssrc = properties.get('ssrc', 0)
        if ssrc in self._mixers:
            # Existing
            print "MIXER: Changing VOLUME"
            self._mixers[ssrc].setVolume( volume )
            self._mixers[ssrc].setPan( pan )
        else:
            print "No input streams available for ssrc:",ssrc
            return
        
        self._mixer_params[ssrc] = (volume, pan)
            
    def _startMessage(self, guid, filename, volume, pan):
        """
            Starts the file stream 
            @param guid: the source globally unique identifier
            @type guid: Number
            @param filename: name of the file to play
            @type filename: String
        """
        self._file_players[guid] = self._file_sender.addFileInput( filename )
        playerid = self._file_players[guid].getID()
        self._file_finished[playerid] = False
        ssrc = self._file_players[guid].getSsrc()
        self._inputs[guid]['ssrc'] = ssrc
        return ssrc
    
    def _startMessage(self, guid, filename, volume, pan):
        self._file_control[guid] = self._file_sender.addFileInput( filename )
        self._file_players[guid] = self._file_control[guid].getMixer()
        self._file_finished[self._file_players[guid].getID()] = False
        self._file_players[guid].setVolume( volume )
        self._file_players[guid].setPan( pan )
        self._file_control[guid].play()

    def onOffline( self, obj, params ):
        """
            Deactivate the pipeline when an object is moved out of the audio play layer 
            or goes offline

            @param params: various parameters of user/service that has gone offline
            @type params: Dictionary
        """
        guid = params['id']
        ssrc = self._inputs[guid]['ssrc']
        if ssrc in self._mixers:
            # if it's an active pipeline stop and return True
            self._mixers[ssrc].remove()


    def onMIC(self, obj, action):
        """
            Called when push to talk is deactivated or when push to talk was inactive
            and message recording stops
            Stops recording from MIC
            @param action: 1 when push to talk on, 2 when attention pressed, 0 when push to talk off
            @type action: Number
        """
        if action in [1,2]:
            print "MIC starting"
            self._mic_controller.micUnmute()
        else:
            print "MIC stopping"
            self._mic_controller.micMute()
        self.emit( 'ack_push_to_talk', action)
            
    def onStartRecord(self, obj, recdata):
        """
            Called when the UI sends a request to start recording.
            @param recdata: dictionary with fields 
                1. 'id': temporary id
        """
        print "OnStartRecord"
        id = recdata['id']
        print "id:",id
        self._mic_controller.startRecord( self.temp_rec_file_name )
        print "Exit StartRecord"
        self.emit('started_record', id)
    
    def onStopRecord(self, obj, recdata):
        """
            Called when the UI sends a request to stop recording.
            @param recdata: dictionary with fields
                1. 'id': temporary id
        """
        
        print "OnStopRecord"
        id = recdata['id']
        self._mic_controller.stopRecord()
        
        detail = {'subcommand':uicon.ADD, 'id':id, 'type':uicon.AUDIOMSG, 'label':'Temp Record Audio', 
                        'url':self.temp_rec_file_name, 'status':-1, 
                        'priority':uicon.PRIORITY_LOW }
        self.onAddInput( None, detail )
        self.emit('stopped_record', id)
        
        
    def onStartPlay(self, obj, playdata):
        """
            Called when the UI sends a request to start playing a message
        """
        print "OnStartPlay"
        print "id:", playdata['id']
        id = playdata['id']
        
        playinfo = {'id':id, 'volume':1, 'pan':0, 'type':uicon.AUDIOMSG }
        self.onChange( None, playinfo )
        self.emit('started_play', id)
        
    def onStopPlay(self, obj, playdata):
        """
            Called when the UI sends a request to stop playing a message
        """
        print 'OnStopPlay'
        print "id", playdata['id']
        id = playdata['id']
        playinfo = {'id':id, 'volume':0, 'pan':0, 'type':uicon.AUDIOMSG }
        self.onChange( None, playinfo )
        self.emit('stopped_play', id)



gobject.type_register( MixerInterface )


class NewMsgController:
    
    def __init__(self, guid, filename):
        print "Start pipeline"
        self.id = guid
        self.filename = filename

    def pause(self):
        print "Pausing msg pipeline"

    def change( self, volume, pan ):
        print volume,"and",pan,"volume change"

    def stop(self):
        print "Stop pipeline"
        
    def play(self):
        print "Start play"


class NewLiveController:

    def __init__(self, guid, address, port):
        print "Start pipeline"
        self.id = guid
        self.address = address
        self.port = port
        
    def pause(self):
        print "Pausing live pipeline"

    def setVolume(self, volume):
        print "changed volume", volume
        
    def setPan( self, pan ):
        print "changed pan", pan

    def stop(self):
        print "Stop pipeline"
        
    def play(self):
        print "Start play"
        
    def remove(self):
        print "Removing live"


